#include"Log.hpp"
#include"Sock.hpp"
#include"Epoll.hpp"
#include<unistd.h>
#include<cassert>
#include<functional>
using namespace bobo;

class EpollServer
{
    using func_t = std::function<void(std::string)>;
public:
    EpollServer(func_t handleRequest, const uint16_t& port = 8080, int revsNum = 1024)
        :_handlerRequest(handleRequest)
        ,_port(port)
        ,_revsNum(revsNum)
    {
        // 1.申请对应的空间
        _revs = new struct epoll_event[_revsNum];
        // 2.创建listensock
        _listenSock = Sock::Socket();
        // 取消TIME_WAIT
        int opt = 1;
        setsockopt(_listenSock, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof opt);
        Sock::Bind(_listenSock, _port);
        Sock::Listen(_listenSock);
        // 3.创建epoll模型
        _epfd = Epoll::CreateEpoll();
        logMessage(DEBUG, "init success, listensock: %d, epfd: %d\n", _listenSock, _epfd); 
        if(!Epoll::CtlEpoll(_epfd, EPOLL_CTL_ADD, _listenSock, EPOLLIN)) exit(6);
        logMessage(DEBUG, "add listensock to epoll success\n");
    }
    void Accepter(int listenSock)
    {
        uint16_t clientPort = 0;
        std::string clientIp;
        int sock = Sock::Accept(listenSock, &clientPort, &clientIp);
        if(sock < 0)
        {
            logMessage(WARNING, "accept error!\n");
            return;
        }
        // 能不能直接读取？不能，因为你并不清楚，底层是否有数据！
        // 将新的sock，添加给epoll
        if(!Epoll::CtlEpoll(_epfd, EPOLL_CTL_ADD, sock, EPOLLIN)) return;
        logMessage(DEBUG, "add new sock : %d to epoll success\n", sock);
    }
    void Recver(int sock)
    {
        // 1.读取数据
        char buffer[10240];
        ssize_t s = recv(sock, buffer, sizeof buffer - 1, 0);
        if(s > 0)
        {
            //假设这里就是读到了一个完整的报文 // 如何保证？？
            buffer[s] = 0;
            _handlerRequest(buffer); // 2.处理数据
        }
        else if(s == 0)
        {
            // 1. 先在epoll中去掉对sock的关心
            bool res = Epoll::CtlEpoll(_epfd, EPOLL_CTL_DEL, sock, 0);
            assert(res);
            (void)res;
            // 2. 再close文件
            close(sock);
            logMessage(NORMAL, "client %d quit, me too...\n", sock);
        }
        else
        {
            // 1. 先在epoll中去掉对sock的关心
            bool res = Epoll::CtlEpoll(_epfd, EPOLL_CTL_DEL, sock, 0);
            assert(res);
            (void)res;
            // 2. 再close文件
            close(sock);
            logMessage(NORMAL, "client recv %d error, close error sock\n", sock);
        }
    }

    void HandlerEvents(int n)
    {
        assert(n);
        for(int i = 0; i < n; ++i)
        {
            uint32_t revents = _revs[i].events;
            int sock = _revs[i].data.fd;
            // 读事件就绪
            if(revents & EPOLLIN)
            {
                if(sock == _listenSock) Accepter(_listenSock); // 1. listensock 就绪
                else Recver(sock);                             // 2. 一般sock 就绪 - read 
            }
            if(revents & EPOLLOUT)
            {
                //TODO?
            }
        }
    }
    void LoopOnce(int timeout)
    {
        int n = Epoll::WaitEpoll(_epfd, _revs, _revsNum, timeout);
        switch(n)
        {
            case 0:
                logMessage(DEBUG, "timeout...\n"); 
                break;
            case -1:
                logMessage(WARNING, "epoll wait error: %s\n", strerror(errno));
                break;
            default:
                // 等待成功
                logMessage(DEBUG, "get a event\n");
                HandlerEvents(n);
                break;
        }
    }
    void start()
    {
        int timeout = -1;
        while(true)
        {
            LoopOnce(timeout);
        }
    }
    ~EpollServer()
    {
        if(_listenSock >= 0) close(_listenSock);
        if(_epfd >= 0) close(_epfd);
        delete[] _revs;
    }
private:
    int _listenSock;
    int _epfd;
    uint16_t _port;
    struct epoll_event* _revs;
    int _revsNum;
    func_t _handlerRequest;
};